package org.streets.commons.util;

import java.util.LinkedList;
import java.util.List;

public class PathUtils {
	
	public static final String UNIX_SEPARATOR = "/";

	public static final String WINDOWS_SEPARATOR = "\\";

	public static final String PARENT_PATH = "..";

	public static final String CURRENT_PATH = ".";

	/**
	 * Apply the given relative path to the given path,
	 * assuming standard Java folder separation (i.e. "/" separators);
	 * @param path the path to start from (usually a full file path)
	 * @param relativePath the relative path to apply
	 * (relative to the full file path above)
	 * @return the full file path that results from applying the relative path
	 */
	public static String applyRelativePath(String path, String relativePath) {
		int separatorIndex = path.lastIndexOf(UNIX_SEPARATOR);
		if (separatorIndex != -1) {
			String newPath = path.substring(0, separatorIndex);
			if (!relativePath.startsWith(UNIX_SEPARATOR)) {
				newPath += UNIX_SEPARATOR;
			}
			return newPath + relativePath;
		}
		else {
			return relativePath;
		}
	}
	
	public static String makeRelativePath(String root, String path) {
		assert path != null;
		if (!path.startsWith(UNIX_SEPARATOR)) {
			path = UNIX_SEPARATOR+path;
		}
		path =toUnixPath(path);
		path = StringUtils.replaceOnce(path, root, "");
		return path;
	}

	public static String toUnixPath(String path) {

		return StringUtils.replace(path, WINDOWS_SEPARATOR, UNIX_SEPARATOR);
	}

	/**
	 * Normalize the path by suppressing sequences like "path/.." and
	 * inner simple dots.
	 * <p>The result is convenient for path comparison. For other uses,
	 * notice that Windows separators ("\") are replaced by simple slashes.
	 * @param path the original path
	 * @return the normalized path
	 */
	public static String cleanPath(String path) {

		String pathToUse = StringUtils.replace(path, WINDOWS_SEPARATOR, UNIX_SEPARATOR);
		// Strip prefix from path to analyze, to not treat it as part of the
		// first path element. This is necessary to correctly parse paths like
		// "file:core/../core/io/Resource.class", where the ".." should just
		// strip the first "core" directory while keeping the "file:" prefix.
		int prefixIndex = pathToUse.indexOf(":");
		String prefix = "";
		if (prefixIndex != -1) {
			prefix = pathToUse.substring(0, prefixIndex + 1);
			pathToUse = pathToUse.substring(prefixIndex + 1);
		}

		String[] pathArray = StringUtils.split(pathToUse, UNIX_SEPARATOR);
		List<String> pathElements = new LinkedList<String>();
		int tops = 0;

		for (int i = pathArray.length - 1; i >= 0; i--) {
			if (CURRENT_PATH.equals(pathArray[i])) {
				// Points to current directory - drop it.
			}
			else if (PARENT_PATH.equals(pathArray[i])) {
				// Registering top path found.
				tops++;
			}
			else {
				if (tops > 0) {
					// Merging path element with corresponding to top path.
					tops--;
				}
				else {
					// Normal path element found.
					pathElements.add(0, pathArray[i]);
				}
			}
		}
		// Remaining top paths need to be retained.
		for (int i = 0; i < tops; i++) {
			pathElements.add(0, PARENT_PATH);
		}

		return prefix + StringUtils.ToDelimitedString(pathElements, UNIX_SEPARATOR);
	}
}
